#pragma once

#include <boost/filesystem.hpp>

#include <cm/config.hpp>

namespace cm {
namespace filesystem {
#ifdef CM_WINDOWS
	inline DWORD get_exe_directory(DWORD sz,char* buf)
	{
		DWORD siz;
		if (sz == 0)
		{
			char dummy_buf[MAX_PATH + 1];
			siz = ::GetModuleFileNameA(NULL,dummy_buf,MAX_PATH);
		}
		else
		{
			siz = ::GetModuleFileNameA(NULL,buf,sz);
		}
		return siz + 1; 
	}
	template< class String >
	boost::system::error_code get_exe_dir_template( String & ph )
	{
		DWORD sz;
		if ( (sz = cm::filesystem::get_exe_directory( 0,static_cast<typename String::value_type*>(0) )) == 0 )
			{ sz = 1; }

		typedef typename String::value_type value_type;

		boost::scoped_array<value_type> buf( new value_type[sz] );
		if (cm::filesystem::get_exe_directory( sz, buf.get() ) == 0 )
			return boost::system::error_code( ::GetLastError(), boost::system::system_category );

		ph = buf.get();
		return boost::system::error_code();
	}
#endif
	inline BOOST_FILESYSTEM_DECL boost::system::error_code get_exe_dir_api( std::string & ph )
	{
		return get_exe_dir_template( ph );
	}

	template< class Path>
	Path exe_path()
	{
		typename Path::external_string_type ph;
		boost::system::error_code ec(get_exe_dir_api(ph));
		if (ec)
		{
			boost::throw_exception(boost::filesystem::basic_filesystem_error<Path>("cm::filesystem::exe_path", ec ));
		}
		return Path(Path::traits_type::to_internal(ph));
	}

	//--------------------------------------------

}}
